package org.rule.exec;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.googlecode.aviator.AviatorEvaluator;
import com.googlecode.aviator.AviatorEvaluatorInstance;
import org.rule.domain.dto.RuleExecDTO;
import org.rule.emum.NodeTpEnum;
import org.rule.emum.OperatorEnum;
import org.rule.function.NumEqualFunction;
import org.rule.function.ObjectNotNullFunction;
import org.rule.function.StrEqualFunction;
import org.rule.function.StrNotEqualFunction;

import java.util.List;
import java.util.Map;

public class RuleExec {
    public static AviatorEvaluatorInstance evaluator ;
    static {
        AviatorEvaluator.addFunction(new NumEqualFunction());
        AviatorEvaluator.addFunction(new ObjectNotNullFunction());
        AviatorEvaluator.addFunction(new StrEqualFunction());
        AviatorEvaluator.addFunction(new StrNotEqualFunction());
        evaluator = AviatorEvaluator.getInstance();
    }
    public static String execute(List<RuleExecDTO> ruleExecDTOList, Object b){
        /**
         * todo 1. 参数校验
         * 一定要有个起点，有个终点
         */
        // 2. 规则执行
        Map<String, Object> map = BeanUtil.beanToMap(b);
        RuleExecDTO executeNode = ruleExecDTOList.stream().filter(f-> StrUtil.equals(f.getNodeTpCd(), NodeTpEnum.START.getCode())).findAny().orElseGet(null);
        Assert.notNull(executeNode, "规则起点未配置");
        map.put("param", executeNode.getSecParam());
        boolean flag = true;
        boolean executeRes = OperatorEnum.getOperator(executeNode.getOperator()).compare(evaluator, map, executeNode);
        String nextNode ;
        while (flag){
            if(executeRes){
                nextNode = executeNode.getSuccessToNextNode();
            }else {
                nextNode = executeNode.getFailedToNextNode();
            }
            String finalNextNode = nextNode;
            executeNode = ruleExecDTOList.stream().filter(f-> StrUtil.equals(f.getNodeId(), finalNextNode)).findAny().orElseGet(null);
            Assert.notNull(executeNode, "规则节点{0}未配置",finalNextNode);
            map.put("param", executeNode.getSecParam());
            if(StrUtil.equals(executeNode.getNodeTpCd(), NodeTpEnum.END.getCode())){
                break;
            }
            executeRes = OperatorEnum.getOperator(executeNode.getOperator()).compare(evaluator, map, executeNode);
        }
        return executeNode.getExecResult();
    }
}
